#include "base_log.h"
#include <spdlog/sinks/rotating_file_sink.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/sinks/basic_file_sink.h>

namespace El {
namespace Base {

Log &Log::GetInstance()
{
    static Log log;
    return log;
}

bool Log::init(const std::string &filename, const std::string &loggerName, int32_t max_size, int32_t max_files)
{
    logFilename_ = filename;
    loggerName_ = loggerName;
    maxSize_ = max_size;
    maxFiles_ = max_files;

    // 只创建控制台日志记录器
    consoleLogger_ = spdlog::stdout_color_mt(loggerName + "_console");

    spdlog::set_pattern("%Y-%m-%d %H:%M:%S.%e %L %s:%# %! %v");
    spdlog::set_level(spdlog::level::trace);

    // 初始化日志记录器
    updateLoggers();

    spdlog::flush_on(spdlog::level::trace);
    return true;
}

void Log::enableFileLogging(bool enable)
{
    if (enable && !fileLoggingEnabled_) {
        // 创建文件日志记录器
        try {
            fileLogger_ = spdlog::rotating_logger_mt(
                loggerName_ + "_file", 
                logFilename_, 
                maxSize_, 
                maxFiles_
            );
        } catch (const spdlog::spdlog_ex& ex) {
            LOG_ERROR("Failed to create file logger: {}", ex.what());
            return;
        }
    }
    
    fileLoggingEnabled_ = enable;
    updateLoggers();
}

bool Log::isFileLoggingEnabled() const
{
    return fileLoggingEnabled_;
}

void Log::updateLoggers()
{
    if (fileLoggingEnabled_ && fileLogger_) {
        // 同时使用文件和控制台记录器
        spdlog::sinks_init_list sink_list = {fileLogger_->sinks().front(), consoleLogger_->sinks().front()};
        auto combined_logger = std::make_shared<spdlog::logger>("combined", sink_list.begin(), sink_list.end());
        spdlog::set_default_logger(combined_logger);
    } else {
        // 只使用控制台记录器
        spdlog::set_default_logger(consoleLogger_);
    }
}

void Log::setLogLevel(LogLevel level)
{
    currentLevel = level;
    spdlog::set_level(toSpdLogLevel(level));
}

LogLevel Log::getLogLevel() const
{
    return currentLevel;
}

void Log::setLogLevel(const std::string level)
{
    if (level == "trace") {
        setLogLevel(LogLevel::BASE_TRACE);
    } else if (level == "debug") {
        setLogLevel(LogLevel::BASE_DEBUG);
    } else if (level == "info") {
        setLogLevel(LogLevel::BASE_INFO);
    } else if (level == "warn") {
        setLogLevel(LogLevel::BASE_WARN);
    } else if (level == "error") {
        setLogLevel(LogLevel::BASE_ERROR);
    } else if (level == "critical") {
        setLogLevel(LogLevel::BASE_CRITICAL);
    } else if (level == "off") {
        setLogLevel(LogLevel::BASE_OFF);
    } else {
        LOG_ERROR("Invalid log level: {}. Available levels: trace, debug, info, warn, error, critical, off", level);
    }
}

spdlog::level::level_enum Log::toSpdLogLevel(LogLevel level)
{
    switch (level) {
        case LogLevel::BASE_TRACE:
            return spdlog::level::trace;
        case LogLevel::BASE_DEBUG:
            return spdlog::level::debug;
        case LogLevel::BASE_INFO:
            return spdlog::level::info;
        case LogLevel::BASE_WARN:
            return spdlog::level::warn;
        case LogLevel::BASE_ERROR:
            return spdlog::level::err;
        case LogLevel::BASE_CRITICAL:
            return spdlog::level::critical;
        case LogLevel::BASE_OFF:
            return spdlog::level::off;
        default:
            return spdlog::level::info;
    }
}

LogLevel Log::fromSpdLogLevel(spdlog::level::level_enum level)
{
    switch (level) {
        case spdlog::level::trace:
            return LogLevel::BASE_TRACE;
        case spdlog::level::debug:
            return LogLevel::BASE_DEBUG;
        case spdlog::level::info:
            return LogLevel::BASE_INFO;
        case spdlog::level::warn:
            return LogLevel::BASE_WARN;
        case spdlog::level::err:
            return LogLevel::BASE_ERROR;
        case spdlog::level::critical:
            return LogLevel::BASE_CRITICAL;
        case spdlog::level::off:
            return LogLevel::BASE_OFF;
        default:
            return LogLevel::BASE_INFO;
    }
}

} // namespace Base
} // namespace El